import tkinter as tk
from tkinter import messagebox
from typing import Dict, Callable
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from grade_manager.models.user import UserManager
from grade_manager.models.grade import GradeManager
from grade_manager.views.login_view import LoginView
from grade_manager.views.main_view import MainView
from grade_manager.utils.dialog_helper import DialogHelper
from grade_manager.utils.charts import MatplotlibCharts


class GradeController:
    #成绩管理系统控制器

    def __init__(self, root: tk.Tk):
        self.root = root
        self.user_manager = UserManager()
        self.grade_manager = GradeManager()
        self.current_user = None

        # 初始化视图
        self.login_view = LoginView(self.root)
        self.main_view = MainView(self.root)

        # 绑定事件
        self._bind_events()

        # 默认显示登录界面
        self.show_login()

    def _bind_events(self):
        # 登录视图事件
        self.login_view.bind_commands(
            login_cmd=self._handle_login,
            register_cmd=self._handle_register
        )

        # 主视图事件
        self.main_view.bind_commands({
            'add': self._show_add_dialog,
            'delete': self._show_delete_dialog,
            'update': self._show_update_dialog,
            'refresh': self._refresh_grades,
            'logout': self._handle_logout,
            'show_chart': self._show_matplotlib_chart,
            'show_credit_pie': self._show_credit_pie,
            'search': lambda: self._handle_search(self.main_view.get_search_keyword()),
            'clear_search': self._handle_clear_search,
            'change_password': self._show_change_password_dialog
        })

    def show_login(self):
        # 显示登录界面
        self.main_view.frame.pack_forget()
        self.login_view.frame.pack(pady=50)
        self.root.title("成绩管理系统 - 登录")

    def show_main(self):
        # 显示主界面
        self.login_view.frame.pack_forget()
        self.main_view.frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
        self.main_view.set_username(self.current_user)
        self._refresh_grades()
        self.root.title(f"成绩管理系统 - {self.current_user}")

    def _handle_login(self):
        # 处理登录
        username, password = self.login_view.get_credentials()

        if not username or not password:
            self.login_view.show_error("用户名和密码不能为空")
            return

        if self.user_manager.authenticate(username, password):
            self.current_user = username
            self.show_main()
        else:
            self.login_view.show_error("登录失败，请检查用户名和密码")

    def _handle_register(self):
        # 处理注册
        username, password = self.login_view.get_credentials()

        if not username or not password:
            self.login_view.show_error("用户名和密码不能为空")
            return

        if self.user_manager.register(username, password):
            messagebox.showinfo("成功", "注册成功，请登录")
        else:
            self.login_view.show_error("注册失败，用户名可能已存在")

    def _handle_logout(self):
        # 处理退出登录
        self.current_user = None
        self.show_login()

    def _show_change_password_dialog(self):
        # 显示修改密码对话框
        DialogHelper.show_input_dialog(
            self.root,
            "修改密码",
            {
                "old_password": "旧密码",
                "new_password": "新密码",
                "confirm_password": "确认新密码"
            },
            self._handle_change_password
        )

    def _handle_change_password(self, data: dict):
        # 处理修改密码请求
        old_password = data.get("old_password", "")
        new_password = data.get("new_password", "")
        confirm_password = data.get("confirm_password", "")

        if not all([old_password, new_password, confirm_password]):
            messagebox.showerror("错误", "所有字段都必须填写")
            return

        if new_password != confirm_password:
            messagebox.showerror("错误", "新密码与确认密码不一致")
            return

        if len(new_password) < 6:
            messagebox.showerror("错误", "密码长度不能少于6位")
            return

        if not self.user_manager.authenticate(self.current_user, old_password):
            messagebox.showerror("错误", "旧密码不正确")
            return

        if self.user_manager.change_password(self.current_user, new_password):
            messagebox.showinfo("成功", "密码修改成功，请重新登录")
            self._handle_logout()
        else:
            messagebox.showerror("错误", "密码修改失败")

    def _handle_search(self, keyword: str):
        # 处理搜索请求
        if not keyword:
            self._refresh_grades()
            return

        all_grades = self.main_view.get_all_grades()
        filtered_grades = {
            subj: info
            for subj, info in all_grades.items()
            if keyword.lower() in subj.lower()
        }

        total_score = 0.0
        total_credit = 0.0
        for info in filtered_grades.values():
            score = info.get('score', 0)
            credit = info.get('credit', 0)
            total_score += score * credit
            total_credit += credit

        weighted_avg = total_score / total_credit if total_credit != 0 else 0.0

        self.main_view.update_grades(
            filtered_grades,
            weighted_avg,
            total_credit,
            is_filtered=True
        )

    def _handle_clear_search(self):
        # 清除搜索条件
        self._refresh_grades()

    def _refresh_grades(self):
        # 刷新成绩显示
        if self.current_user:
            grades = self.grade_manager.get_grades(self.current_user)
            weighted_avg, total_credit = self.grade_manager.calculate_weighted_average(self.current_user)
            self.main_view.update_grades(grades, weighted_avg, total_credit)

    def _show_matplotlib_chart(self):
        # 显示成绩分布直方图
        try:
            grades = self.grade_manager.get_grades(self.current_user)
            if not grades:
                messagebox.showinfo("提示", "没有可显示的成绩数据")
                return

            self.main_view.clear_chart_frame()
            fig = MatplotlibCharts.create_score_distribution(grades)

            canvas = FigureCanvasTkAgg(fig, master=self.main_view.chart_frame)
            canvas.draw()
            canvas.get_tk_widget().pack(
                fill=tk.BOTH,
                expand=True,
                padx=10,
                pady=10
            )

        except ImportError as e:
            messagebox.showerror("依赖错误", f"需要安装matplotlib: {str(e)}")
        except Exception as e:
            messagebox.showerror("错误", f"生成图表失败: {str(e)}")

    def _show_credit_pie(self):
        # 显示学分占比饼图
        try:
            grades = self.grade_manager.get_grades(self.current_user)
            if not grades:
                messagebox.showinfo("提示", "没有可显示的成绩数据")
                return

            self.main_view.clear_chart_frame()
            fig = MatplotlibCharts.create_credit_pie(grades)

            canvas = FigureCanvasTkAgg(fig, master=self.main_view.chart_frame)
            canvas.draw()
            canvas.get_tk_widget().pack(
                fill=tk.BOTH,
                expand=True,
                padx=10,
                pady=10
            )

        except ImportError as e:
            messagebox.showerror("依赖错误", f"需要安装matplotlib: {str(e)}")
        except Exception as e:
            messagebox.showerror("错误", f"生成饼图失败: {str(e)}")

    def _show_add_dialog(self):
        # 显示添加成绩对话框
        DialogHelper.show_input_dialog(
            self.root,
            "添加成绩",
            {"subject": "科目", "score": "成绩", "credit": "学分"},
            lambda data: self._add_grade(data["subject"], data["score"], data["credit"])
        )

    def _show_delete_dialog(self):
        # 显示删除成绩对话框
        DialogHelper.show_input_dialog(
            self.root,
            "删除成绩",
            {"subject": "科目"},
            lambda data: self._delete_grade(data["subject"])
        )

    def _show_update_dialog(self):
        # 显示修改成绩对话框
        DialogHelper.show_input_dialog(
            self.root,
            "修改成绩",
            {"subject": "科目", "score": "新成绩", "credit": "新学分"},
            lambda data: self._update_grade(data["subject"], data["score"], data["credit"])
        )

    def _add_grade(self, subject: str, score: str, credit: str):
        # 添加成绩
        try:
            score_float = float(score)
            credit_float = float(credit)
        except ValueError:
            messagebox.showerror("错误", "成绩和学分必须是数字")
            return

        if not subject:
            messagebox.showerror("错误", "科目不能为空")
            return

        if self.grade_manager.update_grade(self.current_user, subject, score_float, credit_float):
            messagebox.showinfo("成功", f"已添加 {subject} 的成绩: {score} (学分: {credit})")
            self._refresh_grades()
        else:
            messagebox.showerror("错误", "添加成绩失败")

    def _delete_grade(self, subject: str):
        # 删除成绩
        if not subject:
            messagebox.showerror("错误", "科目不能为空")
            return

        if self.grade_manager.delete_grade(self.current_user, subject):
            messagebox.showinfo("成功", f"已删除 {subject} 的成绩")
            self._refresh_grades()
        else:
            messagebox.showerror("错误", "删除成绩失败")

    def _update_grade(self, subject: str, score: str, credit: str):
        # 修改成绩
        try:
            score_float = float(score)
            credit_float = float(credit)
        except ValueError:
            messagebox.showerror("错误", "成绩和学分必须是数字")
            return

        if not subject:
            messagebox.showerror("错误", "科目不能为空")
            return

        if self.grade_manager.update_grade(self.current_user, subject, score_float, credit_float):
            messagebox.showinfo("成功", f"已更新 {subject} 的成绩为: {score} (学分: {credit})")
            self._refresh_grades()
        else:
            messagebox.showerror("错误", "修改成绩失败")